home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1987 / 12 / holub / queue.c < prev    next >
Text File  |  1987-12-21  |  25KB  |  262 lines

  1. #include "kernel.h"                                                                           
  2.                                                                                               
  3. /*------------------------------------------------------------*/                              
  4.                                                                                               
  5. T_QUEUE *t_makequeue( size )                                                                  
  6. int     size;                                                                                 
  7. {                                                                                             
  8.     /* Make a queue for intertask communication and link it                                   
  9.      * into the the queue chain. Return values are  pointer                                   
  10.      * to queue on suceess or TE_NOMEM if Insufficient memory.                                
  11.      * Queues are searched in order of creation so it's best                                  
  12.      * to create the most active queues first. Be sure that                                   
  13.      * multitasking is blocked when tailp is modified (because                                
  14.      * it's static).                                                                          
  15.      */                                                                                       
  16.                                                                                               
  17.     static T_QUEUE *tailp;                                                                    
  18.     T_QUEUE        *p;                                                                        
  19.     void           *malloc();                                                                 
  20.                                                                                               
  21.     t_block();                                                                                
  22.     p = (T_QUEUE *) malloc( sizeof(T_QUEUE)                                                   
  23.                                 + ((size-1) * sizeof(void *)) );                              
  24.     t_release();                                                                              
  25.                                                                                               
  26.     if( !p )                                                                                  
  27.         return (T_QUEUE *) TE_NOMEM;                                                          
  28.                                                                                               
  29.     p->signature = TQ_SIG;                                                                    
  30.     p->next      = NULL;                                                                      
  31.     p->task_h    = NULL;                                                                      
  32.     p->task_t    = NULL;                                                                      
  33.     p->numele    = 0;                                                                         
  34.     p->q_size    = size;                                                                      
  35.     p->headp     = p->queue;                                                                  
  36.     p->tailp     = p->queue;                                                                  
  37.                                                                                               
  38.     t_block();                                                                                
  39.                                                                                               
  40.     if( !T_queues )                                                                           
  41.         T_queues = tailp = p ;                                                                
  42.     else                                                                                      
  43.     {                                                                                         
  44.         tailp->next = p;                                                                      
  45.         tailp       = p;                                                                      
  46.     }                                                                                         
  47.                                                                                               
  48.     t_release();                                                                              
  49.     return p;                                                                                 
  50. }                                                                                             
  51.                                                                                               
  52. /*------------------------------------------------------------*/                              
  53.                                                                                               
  54. int     t_send( q, msg )                                                                      
  55. T_QUEUE *q;             /* Pointer to queue               */                                  
  56. void    *msg;           /* Pointer to message to enqueue  */                                  
  57. {                                                                                             
  58.     /* Send a message and reschedule if necessary.                                            
  59.      *                                                                                        
  60.      * Return Values:                                                                         
  61.      *   TE_NOERR       No error;                                                             
  62.      *   TE_BADARG      Bad q argument.                                                       
  63.      *   TE_QFULL       Queue is full                                                         
  64.      *                                                                                        
  65.      * The message is always enqueued in the indicated queue.                                 
  66.      * Then, if a task is waiting, The message at the head of                                 
  67.      * the queue is dequeued and attached to the task, which                                  
  68.      * is put back into the active list. Finally, if a task                                   
  69.      * was activated, the current process yields. Note,                                       
  70.      * however, that the current task will still be the                                       
  71.      * active task if it's higher priority than the one to                                    
  72.      * which you send a message. The sending task should wait()                               
  73.      * somewhere to make room for the lower-priority task.                                    
  74.      */                                                                                       
  75.                                                                                               
  76.     TCB *task;                                                                                
  77.                                                                                               
  78.     if( q->signature != TQ_SIG )                                                              
  79.         return( TE_BADARG );                                                                  
  80.                                                                                               
  81.     t_block();                                                                                
  82.                                                                                               
  83.     if( q->numele == q->q_size )        /* Queue is full */                                   
  84.     {                                                                                         
  85.         t_release();                                                                          
  86.         return( TE_QFULL );                                                                   
  87.     }                                                                                         
  88.                                                                                               
  89.     /*                                                                                        
  90.      * Enqueue the message.                                                                   
  91.      */                                                                                       
  92.                                                                                               
  93.     ++ q->numele;                                                                             
  94.     if( ++q->tailp >= q->queue + q->q_size )                                                  
  95.         q->tailp = q->queue ;                                                                 
  96.     *(q->tailp) = msg ;                                                                       
  97.                                                                                               
  98.                                                                                               
  99.     if( q->task_h )                                                                           
  100.     {                                                                                         
  101.         /* A task is waiting, dequeue both it and the message,                                
  102.          * attach the message to the task, and reschedule                                     
  103.          */                                                                                   
  104.                                                                                               
  105.         task      = q->task_h;                                                                
  106.         q->task_h = task->next;                                                               
  107.                                                                                               
  108.         --q->numele;                                                                          
  109.         if( ++q->headp >= q->queue + q->q_size )                                              
  110.             q->headp = q->queue;                                                              
  111.                                                                                               
  112.         task->msg    = *(q->headp);                                                           
  113.         task->status = TS_WAIT    ;                                                           
  114.         pq_ins( T_tasks, &task )  ;                                                           
  115.                                                                                               
  116.         t_yield();                                                                            
  117.     }                                                                                         
  118.                                                                                               
  119.     t_release();                                                                              
  120.     return TE_NOERR;                                                                          
  121. }                                                                                             
  122.                                                                                               
  123. /*------------------------------------------------------------*/                              
  124.                                                                                               
  125. void    *t_wait( q, timeout )                                                                 
  126. T_QUEUE *q;                                                                                   
  127. int     timeout;                                                                              
  128. {                                                                                             
  129.     /* Wait for a message to arrive at the queue. If several                                  
  130.      * tasks are waiting at the same queue, the first task                                    
  131.      * in the queue gets the message. Return if no message                                    
  132.      * arrives within timeout system clock ticks.  Maximum                                    
  133.      * timeout is 32,767 ticks. A 0 timeout value                                             
  134.      * means that the subroutine returns immediately                                          
  135.      * (without a reschedule) if no message is waiting                                        
  136.      * in the queue.                                                                          
  137.      *                                                                                        
  138.      * Message requests are queued up in order recieved,                                      
  139.      * without reguard to priority. I've done this both                                       
  140.      * because it's easy and because, in most applications,                                   
  141.      * tasks with different priorities will not be pending                                    
  142.      * on the same queue.                                                                     
  143.      *                                                                                        
  144.      * If a message is present, the routine returns it                                        
  145.      * imediately without yielding, otherwise the current                                     
  146.      * task is removed from the active list and yield()                                       
  147.      * is called.                                                                             
  148.      *                                                                                        
  149.      * Hints: Use this routine to suspend a task for a                                        
  150.      * limited amount of time (as compared to deleteing                                       
  151.      * the task). Just pend on a queue that will never have                                   
  152.      * a message sent to it.                                                                  
  153.      *                                                                                        
  154.      * Normally, a pointer to the message is returned, other                                  
  155.      * return values are:                                                                     
  156.      *                                                                                        
  157.      *   TE_TIMEOUT  on a timeout or if the input value of                                    
  158.      *               timeout is 0 and no message is waiting                                   
  159.      *                                                                                        
  160.      *   TE_NOTASKS  There current task is the only one in                                    
  161.      *               existance. This is a guaranteed deadlock.                                
  162.      */                                                                                       
  163.                                                                                               
  164.     TCB  *new;                                                                                
  165.                                                                                               
  166.     if( q->signature != TQ_SIG )                                                              
  167.         return( TE_BADARG );                                                                  
  168.                                                                                               
  169.     t_block();                                                                                
  170.                                                                                               
  171.     if( q->numele )                                                                           
  172.     {                                                                                         
  173.         /* There's a message waiting in the queue. Dequeue                                    
  174.          * the message and return it immediately. Strictly                                    
  175.          * speaking, we don't have to attach the message                                      
  176.          * to the task, but it's convenient to do it for                                      
  177.          * debugging reasons.                                                                 
  178.          */                                                                                   
  179.                                                                                               
  180.         -- q->numele;                                                                         
  181.         if( ++q->headp >= q->queue + q->q_size )                                              
  182.             q->headp = q->queue ;                                                             
  183.                                                                                               
  184.         T_active->msg    = *(q->headp);                                                       
  185.         T_active->status = TS_WAIT ;                                                          
  186.                                                                                               
  187.         t_release();                                                                          
  188.                                                                                               
  189.         return T_active->msg;                                                                 
  190.     }                                                                                         
  191.     else                            /* No messages waiting  */                                
  192.     {                                                                                         
  193.         if( timeout == 0 )          /* Immediate time out   */                                
  194.         {                                                                                     
  195.             t_release();                                                                      
  196.             return TE_TIMEOUT;                                                                
  197.         }                                                                                     
  198.         else                                                                                  
  199.         {                                                                                     
  200.             /* Enqueue the current task to wait for an                                        
  201.              * incomming message. The pq_del call                                             
  202.              * gets a task to preempt the current one.                                        
  203.              */                                                                               
  204.                                                                                               
  205.             if( !pq_del( T_tasks, &new) )                                                     
  206.             {                                                                                 
  207.                 t_release();            /* No tasks to activate */                            
  208.                 return TE_NOTASKS;                                                            
  209.             }                                                                                 
  210.             else                                                                              
  211.             {                                                                                 
  212.                 T_active->wait      = timeout;                                                
  213.                 T_active->next      = NULL;                                                   
  214.                 T_active->timestamp = T_clock;                                                
  215.                                                                                               
  216.                 if( !q->task_h )                                                              
  217.                     q->task_h = T_active;                                                     
  218.                 else                                                                          
  219.                     q->task_t->next = T_active;                                               
  220.                                                                                               
  221.                 q->task_t = T_active;                                                         
  222.                                                                                               
  223.                 _t_swap_in( new );  /* Returns on either a message being */                   
  224.                                     /* sent to this queue or a timeout.  */                   
  225.                                                                                               
  226.                 return ( T_active->msg ? T_active->msg : TE_TIMEOUT );                        
  227.             }                                                                                 
  228.         }                                                                                     
  229.     }                                                                                         
  230. }                                                                                             
  231.                                                                                               
  232. /*------------------------------------------------------------*/                              
  233.                                                                                               
  234. t_yield()                                                                                     
  235. {                                                                                             
  236.     /* Yield to the highest priority task (if there is one).                                  
  237.      * You can't yield to tasks waiting at queues, only to                                    
  238.      * active ones.                                                                           
  239.      *                                                                                        
  240.      * Returns:                                                                               
  241.      *  TE_NOERR    successfull yield                                                         
  242.      *  TE_NOTASKS  Current task is the only active task                                      
  243.      */                                                                                       
  244.                                                                                               
  245.     TCB *new, *old ;                                                                          
  246.                                                                                               
  247.     t_block();                                                                                
  248.                                                                                               
  249.     if( ! pq_del( T_tasks, &new ) )                                                           
  250.     {                                                                                         
  251.         t_release();                                                                          
  252.         return TE_NOTASKS;                                                                    
  253.     }                                                                                         
  254.                                                                                               
  255.     old = T_active;                                                                           
  256.                                                                                               
  257.     old->timestamp = T_clock ;                                                                
  258.     pq_ins( T_tasks, &old );                                                                  
  259.                                                                                               
  260.     _t_swap_in( new );  /* _t_swap_in() changes T_active to new; */                           
  261.     return TE_NOERR ;                                                                         
  262. }